﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace Qreed.Xna.Font
{
    public class VectorTextComponent : DrawableGameComponent
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="VectorTextComponent"/> class.
        /// </summary>
        /// <param name="game">The Game that the game component should be attached to.</param>
        public VectorTextComponent(Game game) 
            : base(game)
        {}

        /// <summary>
        /// Called when the GameComponent needs to be updated. Override this method with component-specific update code.
        /// </summary>
        /// <param name="gameTime">Time elapsed since the last call to Update</param>
        public override void Update(GameTime gameTime)
        {
            if (_isDirty && Enabled)
                UpdateArrays();

            base.Update(gameTime);
        }

        private void UpdateArrays()
        {
            _transforms = new Matrix[Text.Length];
            _characters = new VectorFontCharacterBase[Text.Length];

            Vector3 offset = Position;

            for (int i = 0; i < Text.Length; i++)
            {
                char c = Text[i];

                _transforms[i] = Matrix.CreateTranslation(offset);

                VectorFontCharacterBase vc = VectorFont[c];

                if (vc != null)
                {
                    _characters[i] = vc;

                    Vector2 kerning = Vector2.Zero;

                    if (i < Text.Length - 1)
                    {
                        char rightChar = Text[i + 1];
                        kerning = VectorFont.GetKerning(c, rightChar);
                    }

                    offset += new Vector3(vc.Advancement.X + kerning.X, 0.0f, 0.0f);
                }
            }

            _isDirty = false;
        }

        /// <summary>
        /// Called when the DrawableGameComponent needs to be drawn. Override this method with component-specific drawing code. Reference page contains links to related conceptual articles.
        /// </summary>
        /// <param name="gameTime">Time passed since the last call to Draw.</param>
        public override void Draw(GameTime gameTime)
        {
            for (int i = 0; i < Text.Length; i++)
            {
                TransformEffect.World = Transforms[i];
                Effect.Begin();

                foreach (EffectPass pass in Effect.CurrentTechnique.Passes)
                {
                    pass.Begin();

                    ((VectorFontCharacterMesh)Characters[i]).Draw();

                    pass.End();
                }

                Effect.End();
            }
        }

        private bool _isDirty = true;

        private ITransformEffect _transformEffect;
        /// <summary>
        /// Gets or sets the effect.
        /// </summary>
        /// <value>The effect.</value>
        public ITransformEffect TransformEffect
        {
            get { return this._transformEffect; }
            set { this._transformEffect = value; }
        }

        /// <summary>
        /// Gets the effect.
        /// </summary>
        /// <value>The effect.</value>
        protected Effect Effect
        {
            get { return (Effect)_transformEffect; }
        }

        private Vector3 _position;
        /// <summary>
        /// Gets or sets the position.
        /// </summary>
        /// <value>The position.</value>
        public Vector3 Position
        {
            get { return this._position; }
            set 
            { 
                this._position = value;
                _isDirty = true;
            }
        }
			
        private string _text;
        /// <summary>
        /// Gets or sets the text.
        /// </summary>
        /// <value>The text.</value>
        public string Text
        {
            get { return this._text; }
            set
            {
                _text = value;
                _isDirty = true;
            }
        }

        private VectorFont _vectorFont;
        /// <summary>
        /// Gets or sets the vector font.
        /// </summary>
        /// <value>The vector font.</value>
        public VectorFont VectorFont
        {
            get { return this._vectorFont; }
            set
            {
                _vectorFont = value;
                _isDirty = true;
            }
        }

        private Matrix[] _transforms;
        /// <summary>
        /// Gets the character translations.
        /// </summary>
        /// <value>The character translations.</value>
        public Matrix[] Transforms
        {
            get { return this._transforms; }
        }

        private VectorFontCharacterBase[] _characters;
        /// <summary>
        /// Gets the characters.
        /// </summary>
        /// <value>The characters.</value>
        public VectorFontCharacterBase[] Characters
        {
            get { return this._characters; }
        }			
    }
}
